/***************************************************
> Copyright (C) 2024 ==KINGYI== All rights reserved.
> File Name: server2.c
> Author:cjy
> Mail: 
> Created Time: 2024年08月18日 星期日 23时23分45秒
***************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "cJSON.h"
#include <sys/epoll.h>
#include <time.h>
#include <signal.h>

#define MAX_EVENTS 10
#define BUF_SIZE 1024
#define HEARTBEAT_TIMEOUT 5000 // 超时时间，单位毫秒
#define HEARTBEAT_INTERVAL 2000 // 发送心跳间隔，单位毫秒

struct data
{
    int type;
    char count[10];
    float num1;
    float num2;
};

struct number
{
    float sum;
};

struct client_data
{
    int fd;
    struct timespec last_heartbeat;
};

void handle_timeout(int signum, struct epoll_event *events, int epollfd, int sock)
{
    // 用于处理超时的信号处理函数
    // 在这里检查每个连接的最后心跳时间
    struct timespec now;
    clock_gettime(CLOCK_MONOTONIC, &now);
    for (int i = 0; i < MAX_EVENTS; i++)
    {
        if (events[i].events & EPOLLIN && events[i].data.fd != sock)
        {
            struct client_data *client = (struct client_data *)malloc(sizeof(struct client_data));
            if (client == NULL)
            {
                perror("malloc");
                exit(-1);
            }
            client->fd = events[i].data.fd;
            long long diff = (now.tv_sec - client->last_heartbeat.tv_sec) * 1000000000LL + now.tv_nsec - client->last_heartbeat.tv_nsec;
            if (diff > HEARTBEAT_TIMEOUT * 1000000LL)
            {
                // 超时，关闭连接
                close(events[i].data.fd);
                epoll_ctl(epollfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
                free(client);
            }
        }
    }
}

int main()
{
    int sock = 0;
    int listen_sock = 0;
    int ret = 0;
    char buf[BUF_SIZE] = {0};
    char *dest;

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == -1) {
        perror("sock");
        exit(-1);
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons(6661);
    addr.sin_addr.s_addr = inet_addr("192.168.198.128");

    ret = bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr));
    if (ret == -1) {
        perror("bind");
        exit(-1);
    }

    listen(sock, 5);

    struct epoll_event ev;
    struct epoll_event events[MAX_EVENTS];

    int conn_sock, nfds, epollfd;

    epollfd = epoll_create1(0);

    if (epollfd == -1) {
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }

    ev.events = EPOLLIN; // 设置读就绪事件
    ev.data.fd = sock;   // 关联监听套接字

    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &ev) == -1) {
        perror("epoll_ctl: listen_sock");
        exit(EXIT_FAILURE);
    }

    // 设置超时信号
    signal(SIGALRM, (void (*)(int))handle_timeout);
    alarm(HEARTBEAT_INTERVAL / 1000); // 设置首次超时时间为心跳间隔

    while (1) {
        nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        if (nfds == -1) {
            perror("epoll_wait");
            exit(EXIT_FAILURE);
        }

        for (int n = 0; n < nfds; n++) {
            if (events[n].data.fd == sock) {
                conn_sock = accept(sock, NULL, NULL);
                if (conn_sock == -1) {
                    perror("accept");
                    exit(EXIT_FAILURE);
                }
                ev.events = EPOLLIN;
                ev.data.fd = conn_sock; // 关联连接套接字
                if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {
                    perror("epoll_ctl: conn_sock");
                    exit(EXIT_FAILURE);
                }
            } else {
                ret = recv(events[n].data.fd, buf, BUF_SIZE, 0);
                if (ret == -1) {
                    perror("recv");
                    exit(-1);
                }
                puts(buf);

                cJSON *json = cJSON_Parse(buf);

                // 检查是否为心跳包
                cJSON *node = cJSON_GetObjectItem(json, "heartbeat");
                if (node != NULL && node->type == cJSON_Number && node->valueint == 1)
                {
                    // 是心跳包，更新最后心跳时间
                    struct client_data *client = (struct client_data *)malloc(sizeof(struct client_data));
                    if (client == NULL)
                    {
                        perror("malloc");
                        exit(-1);
                    }
                    client->fd = events[n].data.fd;
                    clock_gettime(CLOCK_MONOTONIC, &client->last_heartbeat);
                    free(client);

                    // 发送确认心跳的响应
                    cJSON *response = cJSON_CreateObject();
                    cJSON_AddItemToObject(response, "ack", cJSON_CreateNumber(1));
                    dest = cJSON_Print(response);
                    ret = send(events[n].data.fd, dest, strlen(dest), 0);
                    if (ret == -1)
                    {
                        perror("send");
                        exit(-1);
                    }
                    free(dest);
                    cJSON_Delete(response);
                }
                else
                {
                    cJSON *json = NULL;
                    struct data dat;
                    memset(&dat, 0, sizeof(dat));

                    struct number num;
                    memset(&num, 0, sizeof(num));

                    node = cJSON_GetObjectItem(json, "type");
                    if (node == NULL) {
                        printf("can't find type\n");
                        exit(-1);
                    }
                    if (node->type == cJSON_Number) {
                        dat.type = node->valueint;
                    }

                    node = cJSON_GetObjectItem(json, "count");
                    if (node == NULL) {
                        printf("can't find count\n");
                        exit(-1);
                    }
                    if (node->type == cJSON_String) {
                        strcpy(dat.count, node->valuestring);
                    }

                    node = cJSON_GetObjectItem(json, "num1");
                    if (node == NULL) {
                        printf("can't find num1\n");
                        exit(-1);
                    }
                    if (node->type == cJSON_Number) {
                        dat.num1 = node->valuedouble;
                    }

                    node = cJSON_GetObjectItem(json, "num2");
                    if (node == NULL) {
                        printf("can't find num2\n");
                        exit(-1);
                    }
                    if (node->type == cJSON_Number) {
                        dat.num2 = node->valuedouble;
                    }

                    if (dat.type == 1) {
                        num.sum = dat.num1 + dat.num2;
                        printf("%f\n", num.sum);
                    } else if (dat.type == 2) {
                        num.sum = dat.num1 - dat.num2;
                        printf("%f\n", num.sum);
                    } else if (dat.type == 3) {
                        num.sum = dat.num1 * dat.num2;
                        printf("%f\n", num.sum);
                    } else if (dat.type == 4) {
                        num.sum = dat.num1 / dat.num2;
                        printf("%f\n", num.sum);
                    }

                    json = cJSON_CreateObject();
                    cJSON_AddItemToObject(json, "sum", cJSON_CreateNumber(num.sum));

                    dest = cJSON_Print(json);

                    ret = send(events[n].data.fd, dest, strlen(dest), 0);
                    if (ret == -1) {
                        perror("send");
                        exit(-1);
                    }
                    free(dest); // 释放打印出来的字符串
                    cJSON_Delete(json);
                }
            }
        }

        // 重新设置超时
        alarm(HEARTBEAT_INTERVAL / 1000);
    }

    close(sock);
    close(epollfd);
    return 0;
}


